home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / vol6n21.arc / CO.ASM next >
Assembly Source File  |  1987-11-17  |  80KB  |  1,741 lines

  1. ;        Co.asm
  2. ;  Format:   CO [d:][directory]
  3.  
  4. CODE SEGMENT                           ;********************************;
  5. ASSUME CS:CODE,DS:CODE                 ;*                              *;
  6. ORG 100H                               ;*  Requires MASM 2.0 or later  *;
  7.                                        ;*     Remember to EXE2BIN      *;
  8. START:         JMP    BEGINNING        ;*                              *;
  9.                                        ;********************************;
  10.  
  11. ;              DATA AREA
  12. ;              ---------
  13. COPYRIGHT      DB     10,"CO 1.0 (c) 1987 Ziff Communications Co.",13,10
  14. PROGRAMMER     DB     26,"Michael J. Mefford"
  15.  
  16. FIELD_SIZE     EQU    44
  17. BAR_START      EQU    323
  18. COPY_MARK      EQU    26
  19. FCB            EQU    5CH
  20.  
  21. CURRENT_DISK   DB  ?
  22. STATUS_REG     DW  ?
  23. VIDEO_SEG      DW  0B000H
  24. NORMAL         DB  07H
  25. INVERSE        DB  70H
  26. BAR_ATTRIBUTE  DB  70H
  27. CURSOR_TYPE    DW  ?
  28. CUR_VERIFY     DB  0
  29.  
  30. SORT_OFFSET    DW  0
  31. SORT_TABLE     DW  0,12,9,3,13,8,29
  32. SORT_FLAG      DB  0
  33. SEARCH_ATTRIB  DW  17H
  34. CUR_OFFSET     DW  BUFFER
  35. CUR_FILE       DW  ?
  36. END_OFFSET     DW  ?
  37. PAGE_END       DW  21 * 160 + BAR_START
  38. COUNT          DW  0
  39. FILE_CNT       DW  0
  40. LINE           DW  BAR_START
  41. SEARCH_COUNT   DW  ?
  42.  
  43. MARK_CNT       DW     0
  44. FILENAME_END   DW     ?
  45. PURGE_DISK     DB     ?
  46. READ_HANDLE    DW     ?
  47. WRITE_HANDLE   DW     ?
  48. SOURCE_ATTRIB  DW     ?
  49. TARGET_ATTRIB  DW     ?
  50. SIZE_LOW       DW     ?
  51. SIZE_HIGH      DW     ?
  52. SOURCE_TIME    DW     ?
  53. SOURCE_DATE    DW     ?
  54. FILE_NAME      DW     ?
  55. COPY_FLAG      DB     0
  56. DELETE_FLAG    DB     0
  57. RENAME_FLAG    DB     0
  58. VERIFY_FLAG    DB     0
  59.  
  60. DISPATCH_KEY   DB  1,3BH,3CH,3DH,3EH,3FH,40H,4AH,4EH,12H,14H,1FH,20H,2EH,2FH
  61.                DB  31H,32H,41H,42H,43H,44H,47H,48H,49H,4FH,50H,51H,76H,84H
  62. DISPATCH_CNT   EQU $ - DISPATCH_KEY
  63.  
  64. DISPATCH_TABLE DW  EXIT, COPY, DELETE, MOVE, CLEAR_MARK, MARK_BLANK, VERIFY
  65.                DW  UNMARK, MARK, SORT_EXT, SORT_DATE, SORT_SIZE, DELETE
  66.                DW  COPY, VERIFY, SORT_NAME, MOVE, SORT_NAME, SORT_EXT
  67.                DW  SORT_SIZE, SORT_DATE, HOME_BAR, UP_ARROW, PG_UP
  68.                DW  END_BAR, DN_ARROW, PG_DN, BOTTOM_BAR, TOP_BAR
  69. DISPATCH_END   EQU $ - 2
  70.  
  71. NOT_ENOUGH     DB  "Requires 128K free RAM$"
  72. INVALID        DB  "Invalid directory$"
  73. TOO_MANY       DB  "Too many files$"
  74. LOADING        DB  "Loading and Sorting directory.",0
  75. LOAD_ONLY      DB  "Loading directory.",0
  76. DIRECTORY      DB  "Directory of ",0
  77. FILES          DB  4 DUP(32),"File(s)",11 DUP(32),"bytes free",0
  78. DELETE_MSG     DB  " will be deleted.",0,"Do you wish to delete?  Y/N",0
  79. BS             DB  8,32,8,0
  80. DISK_MSG       DB  "Error reading drive ",0
  81.                DB  "(R)etry or (Q)uit",0
  82. MARKED_MSG     DB  " marked files",0
  83. COPY_MSG       DB  "Copy ",0
  84. MOVE_MSG       DB  "Move ",0
  85. TO_MSG         DB  " to...",0
  86. STAR_DOT_STAR  DB  "*.*",0
  87. ON             DB  " ON",0
  88. OFF            DB  "OFF",0
  89. DIRECTORIES    DB  "<DIR>"
  90.  
  91. MENU  LABEL  BYTE
  92. DB  201,20 DUP (205),187,186," PC Magazine CO.COM ",186
  93. DB  186," (C) Copr. 1987 ZD  ",186,186," Michael J. Mefford ",186
  94. DB  199,20 DUP (196),182,          186," F1   Copy          ",186
  95. DB  186," F2   Delete        ",186,186," F3   Move          ",186
  96. DB  186," F4   Clear marks   ",186,186," F5   Mark blank    ",186
  97. DB  186," F6   Verify   OFF  ",186,186," F7   Sort by Name  ",186
  98. DB  186," F8   Sort by Ext.  ",186,186," F9   Sort by Size  ",186
  99. DB  186," F10  Sort by DaTe  ",186,186," +/-  Mark/Unmark   ",186
  100. DB  186," Esc  to Exit       ",186,200,20 DUP (205),188
  101. DB  "  Use: ",24,32,25," PgUp PgDn"
  102. DB  "   ^PgUp ^PgDn Home End "
  103.  
  104. ;----------------------------------------------------------------------------;
  105. ; Some housekeeping first. Since we will be changing the default drive       ;
  106. ; and directory to the requested drive and directory, we need to save the    ;
  107. ; current defaults, so they can be restored.  Install critical error trap.   ;
  108. ;----------------------------------------------------------------------------;
  109.  
  110. ;              CODE AREA
  111. ;              ---------
  112. BEGINNING:     MOV    AX,3301H               ;Turn Control Break off.
  113.                MOV    DL,0
  114.                INT    21H
  115.  
  116.                MOV    AH,54H                 ;Get current verify flag.
  117.                INT    21H
  118.                MOV    CUR_VERIFY,AL          ; and save.
  119.                XOR    AL,AL
  120.                CALL   SET_VERIFY             ;Turn verify off.
  121.  
  122.                MOV    DX,OFFSET DISK_ERROR   ;Install critical error trap.
  123.                MOV    AX,2524H
  124.                INT    21H
  125.  
  126.                CLD                           ;String moves forward.
  127.                CALL   GET_DRIVE              ;Get current drive.
  128.                MOV    CURRENT_DISK,AL        ;Save.
  129.                MOV    SI,OFFSET CURRENT_DIR  ;Get current directory.
  130.                CALL   GET_DIR
  131.  
  132. ;---------------------------------------------------------------------;
  133. ; More housekeeping. We will be writing directly to the screen buffer ;
  134. ; so we need the display card address and the status register.        ;
  135. ;---------------------------------------------------------------------;
  136.  
  137. DISPLAY:       MOV    AX,40H           ;Point to the ROM BIOS data area
  138.                MOV    DS,AX            ; and get base address of active
  139.                MOV    AX,DS:[63H]      ; display card.
  140.                ADD    AX,6             ;Add six to get status register
  141.                PUSH   CS               ;Done there, so restore data segment.
  142.                POP    DS
  143.                MOV    STATUS_REG,AX    ;Store status register.
  144.                CMP    AX,3BAH          ;Status port of MONO card is 3BAh.
  145.                JZ     MONO             ;If that's what we got, it's MONO
  146.                MOV    VIDEO_SEG,0B800H       ; else COLOR so add 800h.
  147.                XOR    BH,BH                  ;Get current attribute
  148.                MOV    AH,8                   ; of display page zero.
  149.                INT    10H
  150.                MOV    NORMAL,AH              ;Store it.
  151.                XOR    AH,1110111B            ;Flip color bits.
  152.                MOV    INVERSE,AH             ;Save it.
  153.                MOV    BAR_ATTRIBUTE,AH
  154. MONO:          XOR    BH,BH
  155.                MOV    AH,3                   ;Retrieve cursor type.
  156.                INT    10H
  157.                MOV    CURSOR_TYPE,CX
  158.  
  159.                MOV    AH,49H                 ;Return our memory segment.
  160.                INT    21H
  161.                MOV    BX,2000H               ;Request 128K.
  162.                MOV    AH,4AH
  163.                INT    21H
  164.                MOV    DX,OFFSET NOT_ENOUGH
  165.                JNC    PARSE
  166.                JMP    ERROR_EXIT             ;If not available, exit.
  167.  
  168. ;----------------------------------------;
  169. ; Parse the command line for parameters. ;
  170. ;----------------------------------------;
  171.  
  172. PARSE:         MOV    SI,81H                 ;Point to first character.
  173.                CMP    BYTE PTR DS:[80H],0    ;Any parameters?
  174.                JNZ    NEXT_SWITCH
  175.                JMP    GET_WORKING            ;If no, skip.
  176.  
  177. NEXT_SWITCH:   LODSB                         ;Get a byte.
  178.                CMP    AL,13                  ;Carriage return?
  179.                JZ     GET_PARA               ;If yes, done here.
  180.                CMP    AL,"/"                 ;Is it switch character?
  181.                JNZ    NEXT_SWITCH            ;If no, get next character.
  182.                LODSB                         ;Get switch character.
  183.                AND    AL,5FH                 ;Capitalize.
  184.                CMP    AL,"R"                 ;If "R", remove directories.
  185.                JNZ    CK_EXT
  186.                MOV    SEARCH_ATTRIB,7
  187. CK_EXT:        CMP    AL,"E"                 ;If "E", sort by extension.
  188.                JNZ    CK_SIZE
  189.                MOV    SORT_OFFSET,4
  190. CK_SIZE:       CMP    AL,"S"                 ;If "S", sort by size.
  191.                JNZ    CK_DATE
  192.                MOV    SORT_OFFSET,8
  193. CK_DATE:       CMP    AL,"D"                 ;If "D", sort by date.
  194.                JZ     GOT_DATE
  195.                CMP    AL,"T"                 ;If "T", sort by date.
  196.                JNZ    CK_ORIGINAL
  197. GOT_DATE:      MOV    SORT_OFFSET,12
  198.  
  199. CK_ORIGINAL:   CMP    AL,"O"                 ;If "O", don't sort at all.
  200.                JNZ    NEXT_SWITCH
  201.                MOV    SORT_FLAG,1
  202.                JMP    SHORT NEXT_SWITCH
  203.  
  204. GET_PARA:      XOR    BL,BL                  ;Assume no drive request.
  205.                MOV    SI,81H                 ;Point to first character.
  206. NEXT_PARSE:    LODSB
  207.                CMP    AL,13                  ;Carriage return or slash?
  208.                JZ     GET_WORKING            ;If yes, done here.
  209.                CMP    AL,"/"
  210.                JZ     GET_WORKING
  211.                CMP    AL,32                  ;Leading space?
  212.                JBE    NEXT_PARSE             ;If yes, get next byte.
  213.  
  214.                MOV    BP,SI                  ;Save start.
  215. NEXT_PARA:     LODSB
  216.                CMP    AL,32                  ;End of parameter?
  217.                JBE    END_PARA               ;If yes, done here.
  218.                CMP    AL,"/"
  219.                JZ     END_PARA
  220.                CMP    AL,":"                 ;Drive request?
  221.                JNZ    NEXT_PARA              ;If no, get next byte.
  222.                MOV    DL,BYTE PTR [SI-2]     ;Else, retrieve request.
  223.                AND    DL,5FH                 ;Capitalize.
  224.                SUB    DL,"A"                 ;Convert to DOS format.
  225.                CALL   CHANGE_DRIVE           ;And change drive.
  226.                JMP    SHORT NEXT_PARA        ;Find end of parameter.
  227.  
  228. END_PARA:      MOV    BYTE PTR DS:[SI-1],0   ;Convert parameter to ASCIIZ.
  229.                MOV    BL,BYTE PTR DS:[SI-2]
  230. GET_WORKING:   MOV    SI,OFFSET WORKING_DIR  ;Store working drive directory.
  231.                CALL   GET_DIR
  232.                CMP    BL,":"                 ;Is there a drive request?
  233.                JZ     MESSAGE                ;If yes, skip directory change.
  234.                CMP    BL,32                  ;Is it a delimiter?
  235.                JBE    MESSAGE                ;If yes, skip.
  236.                MOV    DX,BP                  ;Retrieve start.
  237.                DEC    DX                     ;Adjust.
  238.                CALL   CHANGE_DIR             ;Change directory.
  239.                MOV    DX,OFFSET INVALID
  240.                JC     ERROR_EXIT             ;If error, exit.
  241.  
  242. MESSAGE:       CALL   CLS                    ;Clear screen.
  243.                CALL   CURSOR_OFF             ;Cursor off.
  244.                MOV    SI,OFFSET LOADING      ;Display sorting message.
  245.                MOV    DX,0C19H
  246.                CMP    SORT_FLAG,1            ;Unless not sorted.
  247.                JNZ    DISP_MSG
  248.                MOV    SI,OFFSET LOAD_ONLY    ;Then display loading message.
  249.                MOV    DX,0C1FH
  250. DISP_MSG:      CALL   DISPLAY_TEXT
  251.  
  252.                MOV    DI,OFFSET BUFFER       ;Put space character
  253.                MOV    CX,16000               ; in directory listing
  254.                MOV    AX,2020H               ; buffer.
  255.                REP    STOSW
  256.  
  257. ;------------------------------------------------------------------;
  258. ; Read all the directory filenames and store as records in buffer. ;
  259. ;------------------------------------------------------------------;
  260.  
  261. READ_DIR:      MOV    DX,OFFSET STAR_DOT_STAR
  262.                MOV    CX,SEARCH_ATTRIB
  263.                CALL   FIND_FIRST             ;Find first matching file.
  264.                JC     EXIT                   ;If empty directory, exit.
  265.  
  266. STORE_NAME:    MOV    DI,OFFSET BUFFER + 1   ;Point to buffer.
  267.                MOV    BP,SP                  ;Reserve space for stack.
  268.                SUB    BP,500
  269.                CALL   BUFFER_NAME            ;Convert to directory format.
  270.  
  271. FIND_NEXT:     MOV    AH,4FH                 ;Find next matching.
  272.                INT    21H
  273.                JC     STORE_COUNT            ;If carry, no more names.
  274.                CALL   BUFFER_NAME
  275.                CMP    DI,BP                  ;Are we encroaching the stack?
  276.                JBE    FIND_NEXT              ;If no, find next.
  277.                MOV    DX,OFFSET TOO_MANY     ;Else, exit with message.
  278.  
  279. ;-----------------------------------------------------------------------;
  280. ; This is the exit routine. Restore the defaults the way we found them. ;
  281. ;-----------------------------------------------------------------------;
  282.  
  283. ERROR_EXIT:    MOV    AH,9                   ;Display error message.
  284.                INT    21H
  285.                MOV    AL,1                   ;Error code of one.
  286.                JMP    SHORT TERMINATE
  287.  
  288. EXIT:          CALL   CLS                    ;Clear screen.
  289.                XOR    DX,DX                  ;Set cursor top left.
  290.                CALL   SET_CURSOR
  291.                CALL   CURSOR_ON              ;Turn cursor back on.
  292.                XOR    AL,AL                  ;Error code of zero.
  293. TERMINATE:     PUSH   AX
  294.                MOV    AL,CUR_VERIFY          ;Restore verify state.
  295.                CALL   SET_VERIFY
  296.                MOV    DL,CURRENT_DISK        ;Restore drive.
  297.                CALL   CHANGE_DRIVE
  298.                POP    AX
  299.                MOV    AH,4CH
  300.                INT    21H
  301.  
  302. ;-----------------------------------;
  303. ; Store buffer end address and page ;
  304. ; end then sort the filenames.      ;
  305. ;-----------------------------------;
  306.  
  307. STORE_COUNT:   DEC    DI
  308.                MOV    END_OFFSET,DI          ;Store ending offset.
  309.                MOV    BX,COUNT               ;Retrieve file count.
  310.                CMP    BX,21                  ;Enough to fill one page?
  311.                JAE    DO_SORT                ;If yes, use default setting.
  312.                MOV    AX,160                 ;Calculate last record.
  313.                MUL    BL
  314.                ADD    AX,BAR_START           ;Add bar offset.
  315.                MOV    PAGE_END,AX
  316. DO_SORT:       CMP    SORT_FLAG,1            ;Should we sort or leave original?
  317.                JZ     READY                  ;If it was "/O", don't sort.
  318.                CALL   SORT
  319.  
  320. ;------------------------------------------------------------------------;
  321. ; Now, we are ready to get target directory and display it and the menu. ;
  322. ;------------------------------------------------------------------------;
  323.  
  324. READY:         MOV    DI,OFFSET PURGE_DIR    ;Point to storage.
  325.                CALL   GET_DRIVE              ;Get drive.
  326.                MOV    PURGE_DISK,AL
  327.                ADD    AL,"A"                 ;Convert to ASCII.
  328.                STOSB
  329.                MOV    AL,":"                 ;Add colon.
  330.                STOSB
  331.                MOV    SI,DI                  ;Get directory.
  332.                CALL   GET_DIR
  333.                MOV    SI,OFFSET PURGE_DIR    ;Make a carbon copy of
  334.                MOV    DI,OFFSET SOURCE       ; directory.
  335. CARBON_COPY:   MOVSB
  336.                CMP    BYTE PTR [SI],0
  337.                JNZ    CARBON_COPY
  338.                MOV    AL,"\"                 ;Add "\" to end of path
  339.                CMP    [DI-1],AL              ; if not root directory.
  340.                JZ     STORE_END
  341.                STOSB
  342. STORE_END:     MOV    FILE_NAME,DI           ;Store end of path to tack
  343.                CALL   UPDATE_FREE            ; on filename later on.
  344.                MOV    DX,OFFSET WORKING_DIR  ;Restore the working directory.
  345.                CALL   CHANGE_DIR
  346.                MOV    DL,CURRENT_DISK        ;Restore to default drive
  347.                CALL   CHANGE_DRIVE
  348.                MOV    DX,OFFSET CURRENT_DIR  ; and default directory.
  349.                CALL   CHANGE_DIR
  350.                CALL   REFRESH_DIR            ;Display drive, directory, menu.
  351.  
  352. ;-----------------------------------------;
  353. ; We are ready for business now. We will  ;
  354. ; loop here, waiting for user keystrokes. ;
  355. ;-----------------------------------------;
  356.  
  357. GET_KEY:       CALL   UPDATE_SCREEN
  358.                CALL   READ_KEY               ;Get a keystroke.
  359.                MOV    BX,AX                  ;Save returned key.
  360.                CMP    AH,1                   ;Is it Esc or below?
  361.                JBE    FUNCTION               ;If yes, function.
  362.                CMP    AH,36H                 ;Is it right shift or above?
  363.                JAE    FUNCTION               ;If yes, function.
  364.                CMP    AH,1CH                 ;Is it CR?
  365.                JZ     FUNCTION               ;If yes, function.
  366.                MOV    AH,2                   ;Get shift state.
  367.                INT    16H
  368.                TEST   AL,4                   ;Is Ctrl depressed?
  369.                JNZ    FUNCTION               ;If no, check function request.
  370.                CALL   SEARCH                 ;Else, search for first letter.
  371.                JMP    SHORT GET_KEY
  372. FUNCTION:      MOV    DI,OFFSET DISPATCH_KEY
  373.                MOV    AL,BH
  374.                MOV    CX,DISPATCH_CNT        ;Valid commands.
  375.                REPNZ  SCASB
  376.                JNZ    GET_KEY                ;If no match, get another.
  377.                MOV    DI,OFFSET DISPATCH_END
  378.                SHL    CX,1
  379.                SUB    DI,CX
  380.                CALL   DS:[DI]                ;Else do subroutine.
  381.                JMP    SHORT GET_KEY          ;Update screen; get next command.
  382.  
  383.                ;*************;
  384.                ; SUBROUTINES ;
  385.                ;*************;
  386.  
  387. ;---------------------------------------------------------------;
  388. ; This subroutine copies either the highlighted or marked file. ;
  389. ;---------------------------------------------------------------;
  390.  
  391. COPY:          CALL   COUNT_MARKS            ;Count marks.
  392.                CMP    CX,0                   ;Any marked files?
  393.                JNZ    COPY_DEST              ;If yes, display "Copy" message.
  394.                CALL   GET_NAME               ;Is the highlighted a directory?
  395.                JC     COPY_ERROR             ;If yes, exit.
  396. COPY_DEST:     MOV    DX,172FH
  397.                MOV    SI,OFFSET COPY_MSG
  398.                CALL   DISPLAY_TEXT
  399.                CALL   DESTINATION            ;Ask user for destination.
  400.                JC     END_COPY               ;If Esc pressed, exit.
  401.                MOV    COPY_FLAG,1            ;Else, indicate copy.
  402.                CALL   EXEC_MARKED            ;Execute the command.
  403.                MOV    COPY_FLAG,0            ;Restore copy flag.
  404. END_COPY:      RET
  405.  
  406. COPY_ERROR:    CALL   BEEP
  407.                RET
  408.  
  409. ;----------------------------------------------------------------;
  410. ; This subroutine deletes either the highlighted or marked file. ;
  411. ;----------------------------------------------------------------;
  412.  
  413. DELETE:        MOV    DX,172FH               ;Postion cursor for display.
  414.                CALL   SET_CURSOR
  415.                CALL   COUNT_MARKS            ;Get count of marked files.
  416.                CMP    CX,0                   ;Any marked?
  417.                JNZ    DELETE_MARKED          ;If marked, display number marked.
  418.                CALL   GET_NAME               ;Else get highlighted.
  419.                JC     DELETE_ERROR           ;If it's a directory exit.
  420.                CMP    BYTE PTR [SI+39],"H"   ;If it's a hidden file exit.
  421.                JZ     DELETE_ERROR
  422.                MOV    SI,FILE_NAME           ;Else display filename.
  423.                JMP    SHORT DISP_DELETE
  424.  
  425. DELETE_MARKED: MOV    AX,CX                  ;Display count of marked files.
  426.                CALL   GET_COUNT
  427.                MOV    SI,OFFSET MARKED_MSG   ;Display "marked files".
  428. DISP_DELETE:   CALL   GET_TEXT
  429.                MOV    SI,OFFSET DELETE_MSG   ;Display "will be deleted".
  430.                CALL   GET_TEXT
  431.                MOV    DX,182FH               ;Display warning message.
  432.                CALL   DISPLAY_TEXT
  433.  
  434. QUERY:         CALL   READ_KEY               ;Get a keystroke.
  435.                CMP    AH,31H                 ;Is it "N"?
  436.                JZ     DELETE_END             ;If yes, exit delete.
  437.                CMP    AH,1                   ;Is it Esc?
  438.                JZ     DELETE_END             ;If yes, exit delete.
  439.                CMP    AH,15H                 ;Is it "Y"?
  440.                JZ     DELETE_FILE            ;If yes, delete
  441.                CALL   BEEP                   ;Else, beep.
  442.                JMP    SHORT QUERY            ;And get another keystroke.
  443.  
  444. DELETE_FILE:   MOV    DELETE_FLAG,1          ;Indicate deletion.
  445.                CALL   EXEC_MARKED            ;Execute the command.
  446.                MOV    DELETE_FLAG,0          ;Restore deletion flag.
  447. DELETE_END:    CALL   CLEAR_MSG
  448.                RET
  449.  
  450. DELETE_ERROR:  CALL   BEEP                   ;Beep if error.
  451.                RET
  452.  
  453. ;--------------------------------------------------------------;
  454. ; This subroutine moves either the highlighted or marked file. ;
  455. ;--------------------------------------------------------------;
  456.  
  457. MOVE:          CALL   COUNT_MARKS            ;Get count of marked files.
  458.                CMP    CX,0                   ;Any files marked?
  459.                JNZ    MOVE_DEST              ;If yes, display message.
  460.                CALL   GET_NAME               ;Else, see if highlighted is a
  461.                JC     MOVE_ERROR             ; directory; If yes, exit.
  462. MOVE_DEST:     MOV    DX,172FH
  463.                MOV    SI,OFFSET MOVE_MSG     ;Display move message.
  464.                CALL   DISPLAY_TEXT
  465.                CALL   DESTINATION            ;Get user response.
  466.                JC     END_MOVE               ;If Esc pressed, exit.
  467.                MOV    AL,CURRENT_DISK        ;Else, check if move across drives.
  468.                ADD    AL,"A"                   ;Get default drive.
  469.                CMP    BYTE PTR ENTRY + 1,":"   ;Is there a drive specified?
  470.                JNZ    CK_DRIVE                 ;If not, use default.
  471.                MOV    AL,ENTRY               ;Else, use user drive.
  472.                AND    AL,5FH                 ;Capitalize.
  473. CK_DRIVE:      CMP    AL,SOURCE              ;Is it the same as source?
  474.                JZ     JUST_RENAME            ;If yes, rename.
  475. COPY_DELETE:   MOV    COPY_FLAG,1            ;Else, indicate both copy/delete.
  476.                MOV    DELETE_FLAG,1
  477. JUST_RENAME:   MOV    RENAME_FLAG,1
  478. EXEC_MOVE:     CALL   EXEC_MARKED            ;Execute the command.
  479.                MOV    DELETE_FLAG,0          ;Restore all flags.
  480.                MOV    COPY_FLAG,0
  481.                MOV    RENAME_FLAG,0
  482. END_MOVE:      RET
  483.  
  484. MOVE_ERROR:    CALL   BEEP
  485.                RET
  486.  
  487. ;-----------------------------------;
  488. ; This subroutine clears all marks. ;
  489. ;-----------------------------------;
  490.  
  491. CLEAR_MARK:    MOV    SI,OFFSET BUFFER       ;Point to start of listing.
  492. NEXT_CLEAR:    MOV    BYTE PTR [SI],32       ;Write space over mark.
  493.                ADD    SI,FIELD_SIZE          ;Next record.
  494.                CMP    SI,END_OFFSET          ;End of listing?
  495.                JB     NEXT_CLEAR             ;If no, continue until done.
  496.                RET
  497.  
  498. ;----------------------------------------------------------------------;
  499. ; This subroutine marks all files that aren't marked with an asterisk. ;
  500. ;----------------------------------------------------------------------;
  501.  
  502. MARK_BLANK:    MOV    SI,OFFSET BUFFER       ;Point to start of listing.
  503. NEXT_BLANK:    CMP    BYTE PTR [SI+14],"<"   ;Is it a directory?
  504.                JZ     LOOP_MARK              ;If yes, skip.
  505.                CMP    BYTE PTR [SI+40],"H"   ;Is it a hidden file?
  506.                JZ     LOOP_MARK              ;If yes, skip.
  507.                CMP    BYTE PTR [SI],32       ;Is it blank (a space)?
  508.                JNZ    LOOP_MARK                 ;If no, skip.
  509.                MOV    BYTE PTR [SI],COPY_MARK   ;Else mark.
  510. LOOP_MARK:     ADD    SI,FIELD_SIZE             ;Next record.
  511.                CMP    SI,END_OFFSET          ;Continue until done.
  512.                JB     NEXT_BLANK
  513.                RET
  514.  
  515. ;--------------------------------------------------------;
  516. ; This subroutine marks or unmarks the highlighted file. ;
  517. ;--------------------------------------------------------;
  518.  
  519. MARK:          MOV    DL,COPY_MARK           ;Right arrow character.
  520.                JMP    SHORT STORE_MARK
  521.  
  522. UNMARK:        MOV    DL,32                  ;Space character.
  523.  
  524. STORE_MARK:    CALL   GET_NAME               ;Get filename.
  525.                JC     MARK_END               ;If directory, skip.
  526.                CMP    BYTE PTR [SI+39],"H"   ;Is it a hidden file?
  527.                JZ     MARK_END               ;If yes, skip.
  528.                MOV    [SI-1],DL              ;Else store the character.
  529. MARK_END:      CALL   DN_ARROW               ;And move down a row.
  530.                RET
  531.  
  532. ;------------------------------------------------; 
  533. ; This subroutine toggles the copy verify state. ;
  534. ;------------------------------------------------;
  535.  
  536. VERIFY:        XOR    VERIFY_FLAG,1               ;Toggle flag.
  537.                MOV    DI,OFFSET MENU+(10*22)+16   ;Point to menu.
  538.                MOV    SI,OFFSET ON                ;Assume "ON".
  539.                MOV    AL,1
  540.                CMP    VERIFY_FLAG,1               ;Is it on?
  541.                JZ     TOGGLE                      ;If yes, store.
  542.                MOV    SI,OFFSET OFF               ;Else, store "OFF".
  543.                XOR    AL,AL
  544.  
  545. TOGGLE:        MOV    CX,3
  546.                REP    MOVSB
  547.                CALL   SET_VERIFY
  548.                CALL   REFRESH_MENU                ;Display.
  549.                RET
  550.  
  551. ;----------------------------------------------------;
  552. ; This subroutine counts the number of marked files. ;
  553. ;----------------------------------------------------;
  554.  
  555. COUNT_MARKS:   XOR    CX,CX                  ;Zero out counter.
  556.                MOV    SI,OFFSET BUFFER          ;Point to start of listing.
  557. NEXT_COPY:     CMP    BYTE PTR [SI],COPY_MARK   ;Is it marked?
  558.                JNZ    LOOP_COPY                 ;In no, skip.
  559.                INC    CX                     ;Else, increment counter.
  560. LOOP_COPY:     ADD    SI,FIELD_SIZE          ;Next record.
  561.                CMP    SI,END_OFFSET          ;Continue until done.
  562.                JB     NEXT_COPY
  563.                MOV    MARK_CNT,CX            ;Store the count of marked files.
  564.                RET
  565.  
  566. ;---------------------------------------------;
  567. ; This subroutine prompts the user for the    ;
  568. ; destination of highlighted or marked files. ;
  569. ;---------------------------------------------;
  570.  
  571. DESTINATION:   CALL   GET_NAME               ;Get filename.
  572.                MOV    SI,FILE_NAME
  573.                MOV    AX,MARK_CNT            ;Retrieve count of marked files.
  574.                CMP    AX,0                   ;Were there any?
  575.                JZ     DISP_SOURCE            ;If no, display source filename.
  576.                CALL   GET_COUNT              ;Else, display count of marked.
  577.                MOV    SI,OFFSET MARKED_MSG   ;Display "marked files".
  578. DISP_SOURCE:   CALL   GET_TEXT
  579.                MOV    SI,OFFSET TO_MSG       ;Display "to..."
  580.                CALL   GET_TEXT
  581.                MOV    DX,182FH
  582.                CALL   CLEAR_OLD              ;Remove last user entry.
  583.  
  584. GET_DEST:      CALL   READ_KEY               ;Get a keystroke.
  585.                CMP    AL,27                  ;Is it Esc?
  586.                JZ     ABORT_DEST             ;If yes, abort.
  587.                CMP    AL,13                  ;Is it carriage return?
  588.                JZ     DO_DEST                ;If yes, execute.
  589.                CMP    AL,8                   ;Is it backspace?
  590.                JNZ    NOT_BS3                ;If yes, backspace.
  591.                CALL   MOVE_BS
  592.                JMP    SHORT GET_DEST
  593. NOT_BS3:       CMP    AL,32                  ;Is it above space?
  594.                JBE    GET_DEST               ;If no, ignore.
  595.                CMP    DI,OFFSET ENTRY + 32   ;Else, is 32 line entry field full?
  596.                JZ     GET_DEST               ;If yes, ignore.
  597.                STOSB                         ;Else, store the character.
  598.                CALL   WRITE_TEXT             ;And display it.
  599.                JMP    SHORT GET_DEST
  600.  
  601. ABORT_DEST:    CALL   CURSOR_OFF
  602.                CALL   CLEAR_MSG
  603.                STC
  604.                RET
  605.  
  606. DO_DEST:       CLC
  607.                RET
  608.  
  609. ;------------------------------------------------------------------------------;
  610. ; This subroutine either copies moves or deletes a highlighted or marked file. ;
  611. ;------------------------------------------------------------------------------;
  612.  
  613. EXEC_MARKED:   CALL   CURSOR_OFF             ;Turn cursor off.
  614.                CMP    MARK_CNT,0             ;Are there any files marked?
  615.                JNZ    MANY_MARKS             ;If yes, go find them.
  616.                MOV    MARK_CNT,1             ;Else, change loop counter to one.
  617.                CALL   GET_NAME
  618.                JMP    SHORT EXEC_BAR         ;And execute it one time.
  619.  
  620. MANY_MARKS:    CALL   HOME_BAR               ;Home the highlight bar.
  621. CK_MARK:       CALL   UPDATE_SCREEN          ;Update the screen.
  622.                CALL   GET_NAME                   ;Get the highlighted filename.
  623.                CMP    BYTE PTR [SI-1],COPY_MARK  ;Is it marked?
  624.                JZ     EXEC_BAR                   ;If yes, execute command.
  625.                CALL   DN_ARROW               ;Else, move down a row.
  626.                JMP    SHORT CK_MARK          ;And check it for a mark.
  627.  
  628. EXEC_BAR:      CMP    BYTE PTR [SI+39],"H"   ;Is it a hidden file?
  629.                JZ     EXEC_ERROR             ;If yes, skip.
  630.                CMP    RENAME_FLAG,1          ;Is it a same drive move?
  631.                JNZ    CK_COPY                ;If no, skip renaming.
  632.                CALL   PARSE_ENTRY            ;Else, parse user entry.
  633.                MOV    DX,OFFSET TARGET       ;Point to target.
  634.                MOV    CX,7                   ;Does the file exist?
  635.                CALL   FIND_FIRST
  636.                JNC    EXEC_ERROR             ;If yes, skip
  637.                CMP    COPY_FLAG,1            ;Is it across drives?
  638.                JZ     GO_READ_WRITE          ;Is yes copy/delete.
  639.                MOV    DX,OFFSET SOURCE
  640.                MOV    DI,OFFSET TARGET
  641.                MOV    AH,56H                 ;Else, rename it.
  642.                INT    21H
  643.                JC     EXEC_ERROR             ;Next one if failed.
  644.                JMP    SHORT REMOVE           ;Else, remove it from list.
  645.  
  646. CK_COPY:       CMP    COPY_FLAG,1            ;Is it a copy request?
  647.                JNZ    CK_DELETE              ;If no, check delete.
  648.                CALL   PARSE_ENTRY            ;Else parse user entry.
  649. GO_READ_WRITE: CALL   READ_WRITE             ;Copy the file.
  650.                JC     EXEC_ERROR             ;If failed, skip rest.
  651. MARK_IT:       MOV    SI,CUR_FILE            ;Else, mark with asterisk
  652.                MOV    BYTE PTR [SI-1],"*"
  653. CK_DELETE:     CMP    DELETE_FLAG,1          ;Is it a delete request?
  654.                JNZ    CK_KEYSTROKE           ;If no, skip.
  655.                MOV    DX,OFFSET SOURCE       ;Else, delete the file.
  656.                MOV    AH,41H
  657.                INT    21H
  658.                JC     EXEC_ERROR
  659. REMOVE:        CALL   REMOVE_FILE            ;If successful, remove from list.
  660.                JMP    SHORT CK_KEYSTROKE
  661.  
  662. EXEC_ERROR:    CALL   BEEP
  663.                CALL   DN_ARROW               ;Go to next line.
  664.  
  665. CK_KEYSTROKE:  CALL   CK_KEY                 ;Was a key struck while busy
  666.                JNZ    CLEAR_KEY              ; at our copy, move or delete task?
  667.                DEC    MARK_CNT               ;If yes, abort, else all done?
  668.                JZ     END_EXEC               ;If no, continue until done.
  669.                JMP    CK_MARK
  670.  
  671. CLEAR_KEY:     CALL   READ_KEY               ;Clear the keyboard buffer,
  672.                CALL   CK_KEY                 ; user entry and prompt.
  673.                JNZ    CLEAR_KEY
  674. END_EXEC:      CALL   UPDATE_FREE
  675.                CALL   FILE_COUNT
  676.                CALL   CLEAR_MSG
  677.                RET
  678.  
  679. ;----------------------------------------;
  680. ; This subroutine parses the user entry. ;
  681. ;----------------------------------------;
  682.  
  683. PARSE_ENTRY:   MOV    BP,OFFSET TARGET       ;Point to target storage.
  684.                MOV    DI,BP
  685.                MOV    SI,OFFSET ENTRY        ;Point to user entry.
  686.                CMP    BYTE PTR [SI],0        ;Anything entered?
  687.                JNZ    GET_END                ;If yes, continue.
  688.                JMP    TACK_FILENAME          ;Else, store source name.
  689.  
  690. GET_END:       LODSB                         ;Move user entry into target
  691.                STOSB                         ; workspace.
  692.                CMP    AL,0
  693.                JNZ    GET_END
  694.  
  695.                STD                           ;Reverse string operation.
  696.                DEC    DI                     ;Adjust pointer back one.
  697.                MOV    SI,DI                  ;Make it the source pointer.
  698.                MOV    FILENAME_END,DI        ;And store.
  699. FIND_PATH:     CMP    SI,OFFSET TARGET - 1   ;Are we at start of name?
  700.                JZ     SEARCH_WILD            ;If yes, done here.
  701.                LODSB
  702.                CMP    AL,"\"                 ;Else, is it a path delimiter?
  703.                JZ     FOUND_PATH             ;If yes, mark start of filename.
  704.                CMP    AL,":"                 ;Colon is also a path delimiter.
  705.                JNZ    FIND_PATH
  706.  
  707. FOUND_PATH:    INC    SI                     ;Adjust pointer to end of path.
  708. SEARCH_WILD:   INC    SI
  709.                MOV    BP,SI                  ;And store.
  710.                CLD                           ;String back to forward.
  711.                MOV    DI,FCB                 ;Use file control block for
  712.                MOV    AX,2900H               ; workspace.
  713.                INT    21H                    ;Parse the entry for globals.
  714.                CMP    AL,1                   ;Any wild cards?
  715.                JNZ    CK_PATH                ;If no, check if it's a directory.
  716.  
  717.                MOV    SI,FCB + 1             ;Else, point to first character.
  718.                MOV    DI,BP                  ;Point to target storage.
  719.                MOV    BX,FILE_NAME           ;Point to source.
  720.                MOV    CX,8                   ;Eight characters.
  721. GLOBAL_NAME:   LODSB
  722.                CMP    AL,32                  ;End of name?
  723.                JZ     EXTENSION              ;If yes, do extension.
  724.                CMP    AL,"?"                 ;Wild card?
  725.                JNZ    LOOP_NAME              ;If no, store target character.
  726.                MOV    AL,[BX]                ;Else, replace with source char.
  727.                CMP    AL,"."                 ;Unless end of name.
  728.                JZ     EXTENSION
  729.                CMP    AL,0
  730.                JZ     EXTENSION
  731. LOOP_NAME:     STOSB                         ;Store the character.
  732.                CMP    BYTE PTR [BX],"."      ;Are we at end of source name?
  733.                JZ     NEXT_GLOBAL            ;If yes, don't move pointer.
  734.                INC    BX                     ;Else, point to next source char.
  735. NEXT_GLOBAL:   LOOP   GLOBAL_NAME
  736.  
  737. EXTENSION:     MOV    AL,"."                 ;Filename delimiter.
  738.                STOSB                         ;Store it.
  739. FIND_EXT:      CMP    [BX],AL                ;Was there a dot in source?
  740.                JZ     DO_DOT                 ;If yes do extension.
  741.                CMP    BYTE PTR [BX],0        ;End of source name?
  742.                JZ     DO_EXT                 ;If yes, do extension.
  743.                INC    BX                     ;Else, go to end of name.
  744.                JMP    SHORT FIND_EXT
  745.  
  746. DO_DOT:        INC    BX                     ;Bump pointer past dot.
  747. DO_EXT:        MOV    SI,FCB + 9             ;Point to extension of parsed.
  748.                MOV    CX,3                   ;Three characters.
  749. DO_EXTENSION:  LODSB
  750.                CMP    AL,32                  ;End of parsed?
  751.                JZ     END_GLOBAL             ;If yes, done here.
  752.                CMP    AL,"?"                 ;Wild card?
  753.                JNZ    LOOP_EXT               ;If no, store user character.
  754.                MOV    AL,[BX]                ;Else, store source character.
  755.  
  756. LOOP_EXT:      STOSB
  757.                INC    BX
  758.                LOOP   DO_EXTENSION           ;Do all three extension chars.
  759.  
  760. END_GLOBAL:    XOR    AL,AL                  ;Make it an ASCIIZ.
  761.                STOSB
  762.                JMP    SHORT PARSE_END        ;Done here.
  763.  
  764. CK_PATH:       MOV    DI,BP                  ;Any characters after path
  765.                CMP    BP,FILENAME_END        ; delimiter?
  766.                JZ     TACK_FILENAME          ;If no, tack on source name.
  767.                MOV    DX,OFFSET ENTRY        ;Else, see if it's a directory.
  768.                MOV    CX,10H
  769.                CALL   FIND_FIRST
  770.                JC     PARSE_END              ;If not found, done here.
  771.                CMP    DS:[149],CL            ;If not directory, done here.
  772.                JNZ    PARSE_END
  773.                MOV    DI,FILENAME_END        ;Else, tack on source filename.
  774.                MOV    AL,"\"
  775.                STOSB
  776.  
  777. TACK_FILENAME: MOV    SI,FILE_NAME           ;Source filename.
  778.                MOV    CX,7
  779.                REP    MOVSW
  780. PARSE_END:     RET
  781.  
  782. ;----------------------------------------------------;
  783. ; This section does the reading and writing to disk. ;
  784. ;----------------------------------------------------;
  785.  
  786. READ_WRITE:    MOV    DX,OFFSET SOURCE       ;Point to source filespec.
  787.                XOR    AL,AL                  ;Open file for reading.
  788.                CALL   OPEN_FILE
  789.                JNC    SAVE_HANDLE
  790.                JMP    END_RW                 ;Exit if failed.
  791. SAVE_HANDLE:   MOV    READ_HANDLE,AX         ;Save the handle.
  792.                MOV    CX,7
  793.                CALL   FIND_FIRST             ;Get source
  794.                MOV    SI,149
  795.                LODSB
  796.                XOR    AH,AH
  797.                MOV    SOURCE_ATTRIB,AX       ; attribute
  798.                LODSW
  799.                MOV    SOURCE_TIME,AX         ; time
  800.                LODSW
  801.                MOV    SOURCE_DATE,AX         ; date
  802.                LODSW
  803.                MOV    SIZE_LOW,AX            ; and size
  804.                LODSW
  805.                MOV    SIZE_HIGH,AX           ; and save.
  806.  
  807.                MOV    DX,OFFSET TARGET       ;Point to target filename.
  808.                CALL   FIND_FIRST             ;Does it exist?
  809.                JNC    CK_IF_SAME             ;If yes, see if same as source.
  810.  
  811.                CALL   GET_DISK               ;Else, get disk free space.
  812.                JMP    SHORT CK_FREE          ;Go see if enough room.
  813.  
  814. CK_IF_SAME:    MOV    CL,DS:[149]            ;Get attribute of target
  815.                XOR    CH,CH
  816.                MOV    BP,CX                  ; and save.
  817.                XOR    CX,1                   ;Flip read-only attribute.
  818.                CALL   CHMOD
  819.                MOV    DX,OFFSET SOURCE       ;Now get source attribute.
  820.                CALL   GETMOD
  821.                CMP    CX,SOURCE_ATTRIB       ;See if it has changed.
  822.                PUSHF                         ;Save compare results.
  823.                MOV    DX,OFFSET TARGET       ;Restore target attribute.
  824.                MOV    CX,BP
  825.                CALL   CHMOD
  826.                POPF                          ;Retrieve compare results.
  827.                STC                           ;Assume files are the same.
  828.                JNZ    CLOSE_READ             ;If they are, exit.
  829.                CALL   GET_DISK               ;Else, get free disk space.
  830.                ADD    AX,DS:[154]
  831.                ADC    DX,DS:[156]            ;Target size + disk free.
  832. CK_FREE:       SUB    AX,SIZE_LOW            ;Total - source size.
  833.                SBB    DX,SIZE_HIGH
  834.                JB     CLOSE_READ             ;If negative, not enough room.
  835.  
  836. CREATE:        MOV    DX,OFFSET TARGET       ;Create and truncate target file
  837.                XOR    CX,CX                  ; to zero.
  838.                MOV    AH,3CH
  839.                INT    21H
  840.                JC     CLOSE_READ
  841.                MOV    WRITE_HANDLE,AX        ;Save handle.
  842.                MOV    AX,DS                  ;Point to second 64K segment
  843.                ADD    AX,1000H               ; for read/write buffer.
  844.                MOV    DS,AX
  845.                XOR    DX,DX
  846.  
  847. COPY_READ:     MOV    BX,CS:READ_HANDLE      ;Retrieve read handle.
  848.                MOV    CX,0FFFFH              ;Read up to 64K at a time.
  849.                MOV    AH,3FH
  850.                INT    21H
  851.                JC     COPY_DONE              ;If done, exit.
  852.                CMP    AX,0                   ;If zero, also done.
  853.                JZ     CHANGE_DATE
  854.  
  855.                MOV    BP,AX                  ;Save bytes read.
  856.                MOV    CX,AX                  ;Bytes read into counter.
  857.                MOV    BX,CS:WRITE_HANDLE     ;Retrieve write handle.
  858.                MOV    AH,40H
  859.                INT    21H                    ;Write the buffer to disk.
  860.                JC     COPY_DONE
  861.                CMP    CX,BP                  ;Did we write same number as read?
  862.                STC                           ;Assume we had a problem.
  863.                JNZ    COPY_DONE              ;If no, exit.
  864.                CMP    CX,0FFFFH              ;Was it a full 64K read?
  865.                JZ     COPY_READ              ;If yes, there must be more.
  866. CHANGE_DATE:   MOV    BX,CS:WRITE_HANDLE
  867.                MOV    CX,CS:SOURCE_TIME      ;Else, make time/date same
  868.                MOV    DX,CS:SOURCE_DATE      ; as source.
  869.                MOV    AX,5701H
  870.                INT    21H
  871.  
  872. COPY_DONE:     PUSH   CS                     ;Restore data segment.
  873.                POP    DS
  874.  
  875. CLOSE_WRITE:   PUSHF                         ;Save error if any.
  876.                MOV    BX,WRITE_HANDLE        ;Close write file.
  877.                CALL   CLOSE_FILE
  878.                POP    AX                     ;Retrieve flags.
  879.                JC     CLOSE_READ             ;Close successful?
  880.                XCHG   AH,AL                  ;If no, exit with error, else
  881.                SAHF                          ; retrieve write state.
  882.  
  883. CLOSE_READ:    PUSHF                         ;Save flags.
  884.                MOV    BX,READ_HANDLE         ;Close read file.
  885.                CALL   CLOSE_FILE             ;Return with status of
  886.                POPF                          ; write file.
  887. END_RW:        RET
  888.  
  889. ;------------------------------------------------------------------------;
  890. ; These four subroutines control in which column the sorting will start. ;
  891. ;------------------------------------------------------------------------;
  892.  
  893. SORT_NAME:     MOV    SORT_OFFSET,0
  894.                JMP    SHORT SORT_MSG
  895.  
  896. SORT_EXT:      MOV    SORT_OFFSET,4
  897.                JMP    SHORT SORT_MSG
  898.  
  899. SORT_SIZE:     MOV    SORT_OFFSET,8
  900.                JMP    SHORT SORT_MSG
  901.  
  902. SORT_DATE:     MOV    SORT_OFFSET,12
  903. SORT_MSG:      MOV    DX,1733H
  904.                MOV    SI,OFFSET LOADING+12
  905.                CALL   DISPLAY_TEXT
  906.  
  907. ;------------------------------------------;
  908. ; This subroutine does the actual sorting. ;
  909. ;------------------------------------------;
  910.  
  911. SORT:          CMP    COUNT,1                ;Can't sort one file.
  912.                JZ     SORT_RETURN
  913.                MOV    DX,END_OFFSET          ;End of filenames in DX.
  914.                SUB    DX,44
  915.                MOV    BP,SORT_OFFSET
  916. NEXT_PASS:     MOV    SORT_FLAG,0
  917.                MOV    BX,OFFSET BUFFER + 1   ;Point to start of buffer.
  918.  
  919. NEXT_SORT:     MOV    SI,BX                  ;Source and destination.
  920.                ADD    SI,SORT_TABLE[BP]
  921.                MOV    DI,SI
  922.                ADD    DI,FIELD_SIZE
  923.                CMP    BP,12                  ;Is it special case of date?
  924.                JZ     DO_DATE                ;If yes, go do it.
  925.                MOV    CX,SORT_TABLE[BP+2]
  926. COMPARE:       REPZ   CMPSB                  ;Compare filenames.
  927.                JBE    END_SORT               ;If already in order, skip.
  928.  
  929. SWAP:          MOV    SI,BX                  ;Else, recover pointers.
  930.                DEC    SI
  931.                MOV    DI,SI
  932.                ADD    DI,FIELD_SIZE
  933.                MOV    CX,FIELD_SIZE / 2      ;Exchange the records.
  934. NEXT_SWAP:     MOV    AX,[DI]
  935.                MOVSW
  936.                MOV    [SI-2],AX
  937.                LOOP   NEXT_SWAP
  938.                MOV    SORT_FLAG,1            ;Flag that exchange was made.
  939.  
  940. END_SORT:      ADD    BX,FIELD_SIZE          ;Point to next record.
  941.                CMP    BX,DX                  ;End of top?
  942.                JB     NEXT_SORT              ;If no, bubble sort next.
  943.                SUB    DX,FIELD_SIZE          ;Else, move top down one record.
  944.                CMP    SORT_FLAG,0            ;Was there exchange made?
  945.                JNZ    NEXT_PASS              ;If yes, another pass.
  946. SORT_RETURN:   CALL   CLEAR_MSG
  947.                RET
  948.  
  949. DO_DATE:       MOV    CX,2                   ;Compare year first.
  950.                REPZ   CMPSB
  951.                JA     SWAP                   ;If above, swap.
  952.                JNZ    END_SORT
  953.                SUB    SI,8                   ;Else, adjust and do month/day.
  954.                SUB    DI,8
  955.                MOV    CX,5
  956.                REPZ   CMPSB
  957.                JA     SWAP                   ;If above, swap.
  958.                JNZ    END_SORT
  959.                ADD    SI,10                  ;Else, adjust and do meridian.
  960.                ADD    DI,10
  961.                CMPSB
  962.                JA     SWAP                   ;If above, swap.
  963.                JNZ    END_SORT
  964.                SUB    SI,6                   ;Else, adjust and do time.
  965.                SUB    DI,6
  966.                MOV    CX,5
  967.                CMP    WORD PTR [SI],3231H    ;Is it special case "12:"?
  968.                JZ     CK_MERIDIAN            ;If yes, see if same.
  969.                CMP    WORD PTR [DI],3231H    ;Is destination "12:"?
  970.                JNZ    COMPARE                ;If no, normal compare.
  971.                JMP    SWAP                   ;Else, swap.
  972. CK_MERIDIAN:   CMPSW                         ;Are both "12:"?
  973.                JNZ    END_SORT               ;If no, next record.
  974.                MOV    CX,3                   ;Else compare minutes.
  975.                JMP    SHORT COMPARE
  976.  
  977. ;--------------------------------------------------------------------------;
  978. ; These six subroutines control the bar and page of the directory listing. ;
  979. ;--------------------------------------------------------------------------;
  980.  
  981. UP_ARROW:      MOV    BP,-160                ;Move bar up one line.
  982.                JMP    SHORT BAR_MOVE
  983.  
  984. DN_ARROW:      MOV    BP,160                 ;Move bar down one line.
  985. BAR_MOVE:      CALL   SCROLL_BAR
  986.                RET
  987.  
  988. PG_UP:         MOV    BP,- FIELD_SIZE * 21   ;Move up 21 lines.
  989.                CALL   SCROLL
  990.                JMP    SHORT BOTTOM_BAR
  991.  
  992. PG_DN:         MOV    BP,FIELD_SIZE * 21     ;Move down 21 lines.
  993. MOVE_PAGE:     CALL   SCROLL
  994.                JMP    SHORT TOP_BAR          ;Move bar to top.
  995.  
  996. HOME_BAR:      MOV    CUR_OFFSET,OFFSET BUFFER   ;Move listing to beginning.
  997. TOP_BAR:       MOV    SI,BAR_START               ;And move bar to top.
  998.                CALL   MOVE_BAR
  999.                RET
  1000.  
  1001. END_BAR:       MOV    BX,END_OFFSET          ;Move listing to last page.
  1002.                SUB    BX,21 * FIELD_SIZE
  1003.                CMP    BX,OFFSET BUFFER
  1004.                JBE    BOTTOM_BAR
  1005.                MOV    CUR_OFFSET,BX
  1006. BOTTOM_BAR:    MOV    SI,PAGE_END            ;And move bar to bottom.
  1007.                SUB    SI,160
  1008.                CALL   MOVE_BAR
  1009.                RET
  1010.  
  1011. ;-----------------------------------------------------------------------;
  1012. ; This subroutine searches for a filename with a specific first letter. ;
  1013. ;-----------------------------------------------------------------------;
  1014.  
  1015. SEARCH:        CMP    BL,"a"                 ;Capitalize if lower case.
  1016.                JB     SEARCH_IT
  1017.                CMP    BL,"z"
  1018.                JA     SEARCH_IT
  1019.                AND    BL,5FH
  1020. SEARCH_IT:     CALL   GET_NAME               ;Get current position.
  1021.                XOR    DX,DX                  ;Zero out file counter.
  1022.                MOV    DI,SI                  ;Store current position in DI.
  1023.                MOV    SI,OFFSET BUFFER + 1   ;Point to top of listing.
  1024.                CMP    BYTE PTR [DI],BL       ;Are we currently at a match?
  1025.                JNZ    NEXT_SEARCH            ;If no, start from top.
  1026. FIND_START:    INC    DX                     ;Increment count.
  1027.                ADD    SI,FIELD_SIZE          ;Increment record.
  1028.                CMP    SI,DI                  ;New record?
  1029.                JBE    FIND_START             ;If no, find it.
  1030.  
  1031. NEXT_SEARCH:   CMP    BYTE PTR [SI],BL       ;Got a match?
  1032.                JZ     FOUND_IT               ;If yes, process.
  1033. INC_SEARCH:    ADD    SI,FIELD_SIZE          ;Else, point to next record.
  1034.                INC    DX
  1035.                CMP    BYTE PTR [SI],32       ;End of listing?
  1036.                JNZ    NEXT_SEARCH            ;If no, keep searching.
  1037.                CALL   BEEP                   ;No matches, so beep.
  1038.                RET
  1039.  
  1040. FOUND_IT:      MOV    CX,COUNT               ;Retrieve file count.
  1041.                SUB    CX,DX                  ;Subtract search count.
  1042.                MOV    SEARCH_COUNT,CX        ;And store.
  1043.                MOV    CL,NORMAL              ;Turn off bar for now.
  1044.                MOV    BAR_ATTRIBUTE,CL
  1045.                CALL   END_BAR                ;First move to end.
  1046.                JMP    SHORT FIND_IT
  1047. NEXT_FIND:     CALL   UP_ARROW               ;Move up to matching filename.
  1048. FIND_IT:       DEC    SEARCH_COUNT
  1049.                JNZ    NEXT_FIND
  1050.                MOV    CL,INVERSE             ;Turn bar back on and display.
  1051.                MOV    BAR_ATTRIBUTE,CL
  1052.                XOR    BP,BP
  1053.                CALL   SCROLL_BAR
  1054.                RET
  1055.  
  1056. ;--------------------------------------------------------------------------;
  1057. ; This subroutine gets the highlighted file and converts it to DOS format. ;
  1058. ;--------------------------------------------------------------------------;
  1059.  
  1060. GET_NAME:      MOV    SI,CUR_OFFSET          ;Get top of page.
  1061.                INC    SI                     ;Bump past mark field.
  1062.                MOV    AX,LINE                ;Get location of bar.
  1063.                SUB    AX,BAR_START           ;Adjust.
  1064.                MOV    CL,160                 ;Convert to byte pointer.
  1065.                DIV    CL
  1066.                MOV    CL,FIELD_SIZE
  1067.                MUL    CL
  1068.                ADD    SI,AX                  ;Add to current offset.
  1069.                MOV    CUR_FILE,SI            ;And save pointer.
  1070.                PUSH   SI
  1071.                MOV    DI,FILE_NAME           ;Store the first eight characters.
  1072.                MOV    CX,8
  1073.                CALL   STORE_BYTES
  1074.                INC    SI
  1075.                CMP    BYTE PTR DS:[SI],32    ;End of name?
  1076.                JZ     END_NAME               ;If yes, done here.
  1077.                MOV    AL,"."                 ;Else, add dot.
  1078.                STOSB
  1079.                MOV    CX,3                   ;Three possible characters
  1080.                CALL   STORE_BYTES            ; as extension.
  1081. END_NAME:      MOV    BYTE PTR [DI],0        ;Convert to ASCIIZ.
  1082.                POP    SI
  1083.                CMP    BYTE PTR [SI+13],"<"   ;Is it a directory?
  1084.                STC
  1085.                JZ     NAME_ERROR             ;If yes, indicate so.
  1086.                CLC
  1087. NAME_ERROR:    RET
  1088.  
  1089. STORE_BYTES:   LODSB                         ;Get a character.
  1090.                CMP    AL,32                  ;If it's space, skip.
  1091.                JZ     SKIP_STORE
  1092.                STOSB
  1093. SKIP_STORE:    LOOP   STORE_BYTES
  1094.                RET
  1095.  
  1096. ;-----------------------------------------------------------;
  1097. ; This subroutine moves and turns the cursor on and removes ;
  1098. ; the last user entry in preparation for new input.         ;
  1099. ;-----------------------------------------------------------;
  1100.  
  1101. CLEAR_OLD:     CALL   SET_CURSOR             ;Move cursor.
  1102.                CALL   CURSOR_ON              ;Turn it on.
  1103.                MOV    DI,OFFSET ENTRY        ;Write nulls over old entry.
  1104.                XOR    AX,AX
  1105.                MOV    CX,18
  1106.                REP    STOSW
  1107.                MOV    DI,OFFSET ENTRY        ;Initiate pointer for entry.
  1108.                RET
  1109.  
  1110. ;-----------------------------;
  1111. ; This subroutine backspaces. ;
  1112. ;-----------------------------;
  1113.  
  1114. MOVE_BS:       CMP    DI,OFFSET ENTRY        ;At beginning of field?
  1115.                JZ     MOVE_BS_END            ;If yes, skip.
  1116.                DEC    DI                     ;Else, decrement pointer.
  1117.                MOV    BYTE PTR [DI],0
  1118.                MOV    SI,OFFSET BS           ;Erase last character.
  1119.                CALL   GET_TEXT
  1120. MOVE_BS_END:   RET
  1121.  
  1122. ;------------------------------------------------------------------;
  1123. ; This subroutine removes the filename from the directory listing. ;
  1124. ;------------------------------------------------------------------;
  1125.  
  1126. REMOVE_FILE:   MOV    DI,CUR_FILE            ;Point to filename.
  1127.                DEC    DI                     ;Include mark field.
  1128.                MOV    SI,DI                  ;Move all the records
  1129.                ADD    SI,FIELD_SIZE          ; that follow up one.
  1130. NEXT_RECORD:   MOV    CX,FIELD_SIZE / 2
  1131.                REP    MOVSW
  1132.                CMP    DI,END_OFFSET
  1133.                JB     NEXT_RECORD
  1134.                SUB    DI,FIELD_SIZE
  1135.                MOV    END_OFFSET,DI          ;Store new end.
  1136.                XOR    BP,BP
  1137.                CALL   SCROLL                 ;Update the screen.
  1138.                DEC    COUNT
  1139.                DEC    FILE_CNT               ;Decrement file count.
  1140.                JNZ    MORE_FILES             ;If empty, exit.
  1141.                JMP    EXIT
  1142. MORE_FILES:    CMP    COUNT,21               ;Full page?
  1143.                JAE    REMOVE_END             ;If yes, skip.
  1144.                SUB    PAGE_END,160           ;Else, adjust page end.
  1145.                MOV    SI,PAGE_END
  1146.                SUB    SI,160
  1147.                CMP    SI,LINE                ;Is bar below directory listing?
  1148.                JA     REMOVE_END             ;If no, skip.
  1149.                CALL   MOVE_BAR               ;Else, move bar up one line.
  1150. REMOVE_END:    RET
  1151.  
  1152. ;----------------------------------------------;
  1153. ; This subroutine displays the count of files. ;
  1154. ;----------------------------------------------;
  1155.  
  1156. FILE_COUNT:    MOV    DI,OFFSET FILES        ;Blank out previous count.
  1157.                MOV    AX,2020H
  1158.                STOSW
  1159.                MOV    AX,FILE_CNT
  1160.                XOR    DX,DX
  1161.                CALL   TRANSLATE
  1162.  
  1163. DISPLAY_BYTES: MOV    DX,1806H               ;Row 24; column 6.
  1164.                MOV    SI,OFFSET FILES        ;Display file count.
  1165.                CALL   DISPLAY_TEXT
  1166.                RET
  1167.  
  1168. ;---------------------------------------------------;
  1169. ; This subroutine converts a hex number to decimal. ;
  1170. ;---------------------------------------------------;
  1171.  
  1172. TRANSLATE:     XCHG   AX,DX
  1173.                MOV    BX,10                  ;Convert to decimal.
  1174.                STD                           ;Reverse direction.
  1175. NEXT_COUNT:    MOV    CX,DX
  1176.                XOR    DX,DX
  1177.                DIV    BX
  1178.                XCHG   AX,CX
  1179.                DIV    BX
  1180.                XCHG   AX,DX
  1181.                ADD    AL,"0"                 ;Convert to ASCII.
  1182.                STOSB                         ;Store the remainder.
  1183.                MOV    AX,CX
  1184.                OR     CX,DX
  1185.                JNZ    NEXT_COUNT
  1186.                CLD                           ;Back to forward direction.
  1187.                RET
  1188.  
  1189. ;----------------------------------------------------------------------------;
  1190. ; This subroutine displays the current directory, menu, and number of files. ;
  1191. ;----------------------------------------------------------------------------;
  1192.  
  1193. REFRESH_DIR:   CALL   CLS                    ;Clear the screen.
  1194. REFRESH_MENU:  MOV    SI,OFFSET MENU         ;Point to menu position.
  1195.                MOV    DI,(2*160)+98          ;And to screen position.
  1196.                MOV    BH,20                  ;Display 20 lines of menu.
  1197. NEXT_REFRESH:  MOV    CX,22                  ;22 characters per line.
  1198. NEXT_MENU:     LODSB
  1199.                MOV    BL,AL
  1200.                CALL   WRITE_SCREEN
  1201.                LOOP   NEXT_MENU
  1202.                ADD    DI,116                 ;Next line.
  1203.                DEC    BH
  1204.                JNZ    NEXT_REFRESH
  1205.  
  1206.                MOV    DX,4
  1207.                MOV    SI,OFFSET DIRECTORY    ;Display "Directory ".
  1208.                CALL   DISPLAY_TEXT
  1209.                MOV    SI,OFFSET PURGE_DIR    ;Display working directory.
  1210.                CALL   GET_TEXT
  1211.                CALL   FILE_COUNT             ;Display file count.
  1212.                MOV    BL,INVERSE             ;Put up cursor bar.
  1213.                CALL   BAR
  1214.                RET
  1215.  
  1216. ;-------------------------------------;
  1217. ; This subroutine scrolls the screen. ;
  1218. ;-------------------------------------;
  1219.  
  1220. SCROLL:        MOV    SI,CUR_OFFSET          ;Get current offset.
  1221.                ADD    SI,BP                  ;Add requested direction.
  1222. CK_LOWER:      CMP    SI,OFFSET BUFFER       ;If above start check upper limit.
  1223.                JAE    UPPER_LIMIT
  1224. LOWER_LIMIT:   MOV    CUR_OFFSET,OFFSET BUFFER    ;Else, make it start.
  1225.                JMP    SHORT SCROLL_RETURN         ;And update screen.
  1226.  
  1227. UPPER_LIMIT:   MOV    BX,END_OFFSET                      ;See if beyond end of
  1228.                CMP    BX,OFFSET BUFFER + 21 * FIELD_SIZE ; directory listing.
  1229.                JA     CK_UPPER
  1230.                MOV    CUR_OFFSET,OFFSET BUFFER
  1231.                JMP    SHORT SCROLL_RETURN
  1232.  
  1233. CK_UPPER:      SUB    BX,21 * FIELD_SIZE
  1234.                CMP    SI,BX
  1235.                JBE    END_SCROLL
  1236.                MOV    SI,BX
  1237.  
  1238. END_SCROLL:    MOV    CUR_OFFSET,SI          ;Update current offset.
  1239. SCROLL_RETURN: RET
  1240.  
  1241. ;--------------------------------------------------;
  1242. ; This subroutine scrolls the bar if between start ;
  1243. ; and end of page. Otherwise the page is scrolled. ;
  1244. ;--------------------------------------------------;
  1245.  
  1246. SCROLL_BAR:    MOV    SI,LINE                ;Get current line.
  1247.                ADD    SI,BP                  ;Add requested line.
  1248.                MOV    BP,- FIELD_SIZE        ;Assume below beginning.
  1249.                CMP    SI,BAR_START           ;Is it?
  1250.                JB     SCROLL_PAGE            ;If yes, scroll page instead.
  1251.                MOV    BP,FIELD_SIZE          ;Do the same for end of page.
  1252.                CMP    SI,PAGE_END
  1253.                JAE    SCROLL_PAGE
  1254.                CALL   MOVE_BAR
  1255.                RET
  1256.  
  1257. SCROLL_PAGE:   CALL   SCROLL
  1258.                RET
  1259.  
  1260. ;----------------------------------------------------;
  1261. ; This subroutine does the actual moving of the bar. ;
  1262. ;----------------------------------------------------;
  1263.  
  1264. MOVE_BAR:      MOV    BL,NORMAL              ;Remove old bar.
  1265.                CALL   BAR
  1266.                MOV    LINE,SI                ;And move bar to new line.
  1267.                MOV    BL,BAR_ATTRIBUTE
  1268.                CALL   BAR
  1269.                RET
  1270.  
  1271. BAR:           MOV    DI,LINE                ;Retrieve line.
  1272.                MOV    CX,39                  ;Bar length 39.
  1273. NEXT_BAR:      CALL   WRITE_SCREEN           ;Write the attribute.
  1274.                LOOP   NEXT_BAR
  1275.                RET
  1276.  
  1277. ;-------------------------------------------------;
  1278. ; This subroutine displays the directory listing. ;
  1279. ;-------------------------------------------------;
  1280.  
  1281. UPDATE_SCREEN: XOR    BP,BP
  1282.                MOV    SI,CUR_OFFSET          ;Retrieve starting offset.
  1283.                MOV    DI,2*160               ;Point to row two of screen.
  1284.                MOV    BH,21                  ;21 lines to write.
  1285. NEXT_WRITE:    MOV    CX,FIELD_SIZE          ;44 characters per line.
  1286. NEXT_CHAR:     LODSB                         ;Get a byte.
  1287.                MOV    BL,AL                  ;Save it in BL.
  1288.                CALL   WRITE_SCREEN           ;Write them.
  1289.                LOOP   NEXT_CHAR
  1290.                ADD    DI,160 - FIELD_SIZE * 2   ;Bump pointer to next line.
  1291.                DEC    BH                        ;Do all 21 lines.
  1292.                JNZ    NEXT_WRITE
  1293.                RET
  1294.  
  1295. ;------------------------------------------------------------;
  1296. ; This subroutine displays the directory by writing directly ;
  1297. ; to the screen buffer. To avoid screen noise (snow) on the  ;
  1298. ; color card, the horizontal retrace has to be monitored.    ;
  1299. ;------------------------------------------------------------;
  1300.  
  1301. WRITE_SCREEN:  MOV    DX,STATUS_REG          ;Retrieve status register.
  1302.                MOV    AX,VIDEO_SEG           ;Point to screen segment.
  1303.                MOV    ES,AX
  1304.  
  1305. HORZ_RET:      IN     AL,DX                  ;Get status.
  1306.                TEST   AL,1                   ;Is it low?
  1307.                JNZ    HORZ_RET               ;If not, wait until it is.
  1308.                CLI                           ;No more interrupts.
  1309.  
  1310. HWAIT:         IN     AL,DX                  ;Get status.
  1311.                TEST   AL,1                   ;Is it high?
  1312.                JZ     HWAIT                  ;If no, wait until it is.
  1313.                MOV    AL,BL                  ;Retrieve character; now it's OK
  1314.                STOSB                         ; to write to screen buffer.
  1315.                STI                           ;Interrupts back on.
  1316.                INC    DI                     ;Bump pointer past attribute.
  1317.                PUSH   CS
  1318.                POP    ES
  1319.                RET                           ;Return
  1320.  
  1321. ;-----------------------------------------------------------------------;
  1322. ; These two subroutines clear either the messages or the entire screen. ;
  1323. ;-----------------------------------------------------------------------;
  1324.  
  1325. CLEAR_MSG:     MOV    CX,172CH               ;Row 24; column 43.
  1326.                MOV    DX,184FH               ;Row 25; column 79.
  1327.                JMP    SHORT CLEAR_WINDOW
  1328.  
  1329. CLS:           XOR    CX,CX
  1330.                MOV    DX,184FH               ;Entire screen.
  1331.  
  1332. CLEAR_WINDOW:  PUSH   BP
  1333.                PUSH   BX
  1334.                MOV    BH,NORMAL              ;Clear with original attribute.
  1335.                MOV    AX,600H
  1336.                INT    10H
  1337.                POP    BX
  1338.                POP    BP
  1339.                RET
  1340.  
  1341. ;-----------------------------------------;
  1342. ; These subroutines display the messages. ;
  1343. ;-----------------------------------------;
  1344.  
  1345. DISPLAY_TEXT:  CALL   SET_CURSOR             ;Move cursor.
  1346. GET_TEXT:      LODSB
  1347.                CMP    AL,0                   ;Zero marks end of string.
  1348.                JZ     END_TEXT
  1349.                CALL   WRITE_TEXT
  1350.                JMP    SHORT GET_TEXT
  1351. END_TEXT:      RET
  1352.  
  1353. WRITE_TEXT:    PUSH   SI                     ;BIOS does not save SI.
  1354.                MOV    AH,0EH                 ;Write teletype.
  1355.                INT    10H
  1356.                POP    SI
  1357.                RET
  1358.  
  1359. ;--------------------------------------------------------------;
  1360. ; These two subroutines change the default drive or directory. ;
  1361. ;--------------------------------------------------------------;
  1362.  
  1363. GET_DRIVE:     MOV    AH,19H
  1364.                INT    21H
  1365.                RET
  1366.  
  1367. CHANGE_DRIVE:  MOV    AH,0EH
  1368.                INT    21H
  1369.                RET
  1370.  
  1371. ;---------------------------------------------;
  1372. ; These two subroutines open or close a file. ;
  1373. ;---------------------------------------------;
  1374.  
  1375. OPEN_FILE:     MOV    AH,3DH
  1376.                INT    21H
  1377.                RET
  1378.  
  1379. CLOSE_FILE:    MOV    AH,3EH
  1380.                INT    21H
  1381.                RET
  1382.  
  1383. ;------------------------------------------------; 
  1384. ; This subroutine finds the first matching file. ;
  1385. ;------------------------------------------------;
  1386.  
  1387. FIND_FIRST:    MOV    AH,4EH
  1388.                INT    21H
  1389.                RET
  1390.  
  1391. ;--------------------------------------------------------------;
  1392. ; These two subroutines retrieve or change a file's attribute. ;
  1393. ;--------------------------------------------------------------;
  1394.  
  1395. CHMOD:         MOV    AX,4301H
  1396.                INT    21H
  1397.                RET
  1398.  
  1399. GETMOD:        MOV    AX,4300H
  1400.                INT    21H
  1401.                RET
  1402.  
  1403. ;---------------------------------------------------------; 
  1404. ; This subroutine gets the free disk space of the target. ;
  1405. ;---------------------------------------------------------;
  1406.  
  1407. GET_DISK:      MOV    SI,DX                  ;Retrieve pointer to target file.
  1408.                MOV    DL,-1                  ;Assume default drive.
  1409.                CMP    BYTE PTR [SI+1],":"    ;Is there a drive request?
  1410.                JNZ    GET_FREE               ;If no, get default drive.
  1411.                MOV    DL,[SI]                ;Else, retrieve drive request.
  1412.                AND    DL,5FH                 ;Capitalize.
  1413.                SUB    DL,"A"                 ;Convert to DOS format.
  1414. GET_FREE:      CALL   DISK_FREE              ;Get free bytes.
  1415.                RET
  1416.  
  1417. ;--------------------------------------------------------------;
  1418. ; This subroutine gets the free disk space of the source drive ;
  1419. ;--------------------------------------------------------------;
  1420.  
  1421. UPDATE_FREE:   MOV    DL,PURGE_DIR           ;Get source drive.
  1422.                SUB    DL,"A"                 ;Convert to DOS format.
  1423.                CALL   DISK_FREE              ;Get disk free space.
  1424.                MOV    DI,OFFSET FILES + 20   ;Point to storage.
  1425.                CALL   TRANSLATE              ;Convert hex to decimal and store.
  1426.                RET
  1427.  
  1428. ;----------------------------------------------; 
  1429. ; This subroutine retrieves available clusters ;
  1430. ; and converts it to hexidecimal bytes free.   ;
  1431. ;----------------------------------------------;
  1432.  
  1433. DISK_FREE:     INC    DL                     ;Adjust drive.
  1434.                MOV    AH,36H                 ;Disk free space.
  1435.                INT    21H
  1436.                XOR    DX,DX
  1437.                MUL    BX                     ;Sectors per cluster times clusters
  1438.                MUL    CX                     ;Result times bytes per cluster.
  1439.                RET
  1440.  
  1441. ;------------------------------------------;
  1442. ; This subroutine converts hex to decimal. ;
  1443. ;------------------------------------------;
  1444.  
  1445. GET_COUNT:     MOV    BX,10                  ;Convert to decimal.
  1446.                XOR    CX,CX                  ;Zero in counter.
  1447. GET_NUMBER:    XOR    DX,DX                  ;Zero in high half.
  1448.                DIV    BX
  1449.                ADD    DL,"0"                 ;Convert to ASCII.
  1450.                PUSH   DX                     ;Save results.
  1451.                INC    CX                     ;Also increment count.
  1452.                CMP    AX,0                   ;Are we done?
  1453.                JNZ    GET_NUMBER
  1454.  
  1455. NEXT_NUMBER:   POP    AX                     ;Retrieve numbers.
  1456.                CALL   WRITE_TEXT             ;And write them.
  1457.                LOOP   NEXT_NUMBER
  1458.                RET
  1459.  
  1460. ;---------------------------------------------------------;
  1461. ; These five subroutines move the cursor, get the current ;
  1462. ; directory, beep the speaker, check or get a keystroke.  ;
  1463. ;---------------------------------------------------------;
  1464.  
  1465. SET_CURSOR:    PUSH   SI
  1466.                XOR    BH,BH                  ;Page zero.
  1467.                MOV    AH,2                   ;Set cursor.
  1468.                INT    10H
  1469.                POP    SI
  1470.                RET
  1471.  
  1472. GET_DIR:       MOV    BYTE PTR [SI],"\"      ;DOS doesn't preface directory
  1473.                INC    SI                     ; with slash so we must.
  1474.                XOR    DL,DL
  1475.                MOV    AH,47H                 ;Retrieve default directory.
  1476.                INT    21H
  1477.                RET
  1478.  
  1479. BEEP:          MOV    DL,7                   ;Beep via DOS.
  1480.                MOV    AH,2
  1481.                INT    21H
  1482.                RET
  1483.  
  1484. READ_KEY:      MOV    AH,0                   ;Retrieve keystroke via BIOS.
  1485.                INT    16H
  1486.                RET
  1487.  
  1488. CK_KEY:        MOV    AH,1                   ;Check for keystroke via BIOS.
  1489.                INT    16H
  1490.                RET
  1491.  
  1492. ;-------------------------------------------------------------;
  1493. ; This subroutine waits until a keystroke is pressed and then ;
  1494. ; clears the message.  Keystroke remains in keyboard buffer.  ;
  1495. ;-------------------------------------------------------------;
  1496.  
  1497. DELAY:         CALL   CK_KEY
  1498.                JZ     DELAY
  1499.                CALL   CLEAR_MSG
  1500.                RET
  1501.  
  1502. ;-----------------------------------------------;
  1503. ; These subroutines turn the cursor off and on. ;
  1504. ;-----------------------------------------------;
  1505.  
  1506. CURSOR_OFF:    MOV    CX,2000H
  1507.                JMP    SHORT SET_TYPE
  1508.  
  1509. CURSOR_ON:     MOV    CX,CURSOR_TYPE
  1510.  
  1511. SET_TYPE:      MOV    AH,1
  1512.                INT    10H
  1513.                RET
  1514.  
  1515. ;------------------------------------------------;
  1516. ; This subroutine changes the default directory. ;
  1517. ;------------------------------------------------;
  1518.  
  1519. CHANGE_DIR:    MOV    AH,3BH
  1520.                INT    21H
  1521.                RET
  1522.  
  1523. ;------------------------------------------------;
  1524. ; This subroutine changes the copy verify state. ;
  1525. ;------------------------------------------------;
  1526.  
  1527. SET_VERIFY:    MOV    AH,2EH
  1528.                INT    21H
  1529.                RET
  1530.  
  1531. ;--------------------------------------------------;
  1532. ; This long subroutine stores the filename in DIR  ;
  1533. ; format. That is, filename, bytes, date and time. ;
  1534. ;--------------------------------------------------;
  1535.  
  1536. BUFFER_NAME:   MOV    SI,158                 ;Point to filename.
  1537.                MOV    CX,12                  ;Store 12 bytes of filename.
  1538.                CMP    BYTE PTR [SI],"."      ;Is it a dot directory?
  1539.                JNZ    INC_COUNT              ;If no, it's a file.
  1540.                CMP    BYTE PTR [SI+1],"."    ;Is it a double dot directory?
  1541.                JNZ    DONT_STORE             ;If no, single dot so skip.
  1542.                INC    COUNT                  ;Else, increment total count.
  1543.                LODSB                         ;Store dots and go to file size.
  1544.                STOSB
  1545.                STOSB
  1546.                ADD    DI,10
  1547.                JMP    SHORT FILE_SIZE
  1548. DONT_STORE:    RET
  1549.  
  1550. INC_COUNT:     INC    COUNT                  ;Increment total count.
  1551. NEXT_STORE:    LODSB                         ;Get a byte.
  1552.                CMP    AL,0                   ;End of filename?
  1553.                JZ     END_STORE              ;If yes, finish with blanks.
  1554.                CMP    AL,"."                 ;Is it the period?
  1555.                JNZ    STORE_BYTE             ;If no, store.
  1556.                SUB    CX,3                   ;Else store 3 spaces.
  1557.                MOV    AL,32
  1558.                REP    STOSB
  1559.                ADD    CX,3
  1560.                JMP    SHORT NEXT_STORE       ;Get next byte.
  1561.  
  1562. STORE_BYTE:    STOSB                         ;Store byte.
  1563.                LOOP   NEXT_STORE             ;Get next byte.
  1564. END_STORE:     MOV    AL,32                  ;Pad balance with spaces.
  1565.                REP    STOSB
  1566.  
  1567. FILE_SIZE:     PUSH   DI                     ;Save pointer.
  1568.                TEST   BYTE PTR DS:[149],10H  ;Is it a directory?
  1569.                JZ     STORE_SIZE             ;If no, store size.
  1570.                MOV    SI,OFFSET DIRECTORIES  ;Else, store "<DIR>".
  1571.                INC    DI
  1572.                MOV    CX,5
  1573.                REP    MOVSB
  1574.                JMP    SHORT END_DATE
  1575.  
  1576. STORE_SIZE:    INC    FILE_CNT               ;Increment file count.
  1577.                ADD    DI,8                   ;Move to end of bytes field.
  1578.                MOV    DX,DS:[156]            ;Retrieve high and low words
  1579.                MOV    AX,DS:[154]            ; of bytes.
  1580.                CALL   TRANSLATE              ;Convert to decimal.
  1581.  
  1582. END_DATE:      POP    DI                     ;Retrieve pointer.
  1583.                ADD    DI,11                  ;Move to date field.
  1584. DATE:          MOV    DX,DS:[152]            ;Retrieve date.
  1585.                MOV    AX,DX
  1586.                MOV    CL,5                   ;Shift to lowest bits.
  1587.                ROR    AX,CL
  1588.                AND    AX,0FH                 ;Mask off all but month.
  1589.                MOV    CL,0FFH                ;Flag as no leading zeros.
  1590.                MOV    CH,"-"                 ;Delimiting character.
  1591.                CALL   STORE_WORD             ;Store it.
  1592.  
  1593.                MOV    AX,DX                  ;Retrieve date.
  1594.                AND    AX,1FH                 ;Mask off all but day.
  1595.                MOV    CL,0                   ;Flag include leading zeros.
  1596.                MOV    CH,"-"
  1597.                CALL   STORE_WORD             ;Store it.
  1598.  
  1599.                MOV    AX,DX                  ;Retrieve date for last time.
  1600.                MOV    CL,9
  1601.                ROR    AX,CL
  1602.                AND    AX,7FH                 ;Mask off all but year.
  1603.                ADD    AX,80                  ;Adjust to ASCII.
  1604.                CMP    AX,100                 ;Past year 2000?
  1605.                JB     DISPLAY_DATE           ;If no, display. Else, adjust for
  1606.                SUB    AX,100                 ; next century. (Planning ahead!)
  1607. DISPLAY_DATE:  MOV    CL,0                   ;Display leading zeros.
  1608.                MOV    CH,32
  1609.                CALL   STORE_WORD             ;Store it.
  1610.  
  1611. TIME:          INC    DI                     ;Move to time field.
  1612.                MOV    DX,DS:[150]            ;Retrieve time.
  1613.                MOV    AX,DX
  1614.                MOV    CL,11                  ;Shift to hours bits.
  1615.                ROR    AX,CL
  1616.                AND    AX,1FH                 ;Mask off all but hours.
  1617.                PUSH   AX
  1618.                CMP    AX,12                  ;Past noon?
  1619.                JBE    MERIDIAN
  1620.                SUB    AX,12                  ;If yes, adjust.
  1621. MERIDIAN:      CMP    AX,0                   ;Midnight?
  1622.                JNZ    NOT_MIDNIGHT
  1623.                MOV    AX,12                  ;If yes, adjust.
  1624. NOT_MIDNIGHT:  MOV    CL,0FFH                ;Suppress leading zeros.
  1625.                MOV    CH,":"
  1626.                CALL   STORE_WORD             ;Store it.
  1627.  
  1628.                MOV    AX,DX                  ;Retrieve time.
  1629.                MOV    CL,5                   ;Shift to minutes bits.
  1630.                ROR    AX,CL
  1631.                AND    AX,3FH                 ;Mask off all but minutes.
  1632.                MOV    CL,0
  1633.                POP    DX                     ;Retrieve hours.
  1634.                MOV    CH,"p"                 ;Assume PM.
  1635.                CMP    DX,12                  ;Is it PM?
  1636.                JAE    PM
  1637.                MOV    CH,"a"                 ;If no, AM.
  1638.  
  1639. PM:            CALL   STORE_WORD             ;Store it.
  1640.                MOV    AH,BYTE PTR DS:[149]   ;Get attribute byte.
  1641.                MOV    AL,"H"                 ;Assume it's hidden.
  1642.                TEST   AH,2                   ;Is it?
  1643.                JNZ    HIDDEN                 ;If yes, store "H".
  1644.                MOV    AL,32                  ;Else, store a space.
  1645. HIDDEN:        STOSB
  1646.                MOV    AL,"S"                 ;Assume it's system.
  1647.                TEST   AH,4                   ;Is it?
  1648.                JNZ    SYSTEM                 ;If yes, store "S".
  1649.                MOV    AL,32                  ;Else, store a space.
  1650. SYSTEM:        STOSB
  1651.                MOV    AL,"R"                 ;Assume it's read-only.
  1652.                TEST   AH,1                   ;Is it?
  1653.                JNZ    READ_ONLY              ;If yes, store "R".
  1654.                MOV    AL,32                  ;Else, store a space.
  1655. READ_ONLY:     STOSB
  1656.                MOV    AL,"A"                 ;Assume it's archive.
  1657.                TEST   AH,20H                 ;is it?
  1658.                JNZ    ARCHIVE                ;If yes, store "A".
  1659.                MOV    AL,32                  ;Else store a space.
  1660. ARCHIVE:       STOSB
  1661.                INC    DI                     ;Bump pointer past mark field.
  1662.                RET
  1663.  
  1664. ;-------------------------------;
  1665.  
  1666. STORE_WORD:    MOV    BL,10
  1667.                DIV    BL                     ;Divide by ten.
  1668.                ADD    AX,"00"                ;Convert to ASCII.
  1669.                CMP    CL,0                   ;Are we to display leading zero?
  1670.                JZ     STORE_IT               ;If yes, store as is.
  1671.                CMP    AL,"0"                 ;Is it a leading zero?
  1672.                JNZ    STORE_IT               ;If no, store it.
  1673.                MOV    AL,32                  ;Else, store a space.
  1674. STORE_IT:      STOSW
  1675.                MOV    AL,CH                  ;Store delimiter character also.
  1676.                STOSB
  1677.                RET
  1678.  
  1679. ;-------------------------------------------;
  1680. ; This is the new Critical Error interrupt. ;
  1681. ;-------------------------------------------;
  1682.  
  1683. DISK_ERROR:    STI                           ;Interrupts back on.
  1684.                PUSHF                         ;Save all registers.
  1685.                PUSH   AX
  1686.                PUSH   BX
  1687.                PUSH   CX
  1688.                PUSH   DX
  1689.                PUSH   SI
  1690.                PUSH   DI
  1691.                PUSH   BP
  1692.                PUSH   DS
  1693.                PUSH   ES
  1694.  
  1695.                PUSH   AX                     ;Save failed drive number.
  1696.                MOV    AX,CS
  1697.                MOV    DS,AX                  ;Point to our data segment.
  1698.                MOV    ES,AX
  1699.  
  1700.                CALL   CLEAR_MSG              ;Clear current message.
  1701.                MOV    SI,OFFSET DISK_MSG     ;Display disk error message.
  1702.                MOV    DX,172FH
  1703.                CALL   DISPLAY_TEXT
  1704.                POP    AX                     ;Retrieve fail drive and display.
  1705.                ADD    AL,"A"
  1706.                CALL   WRITE_TEXT
  1707.                MOV    DX,182FH               ;Display rest of error message.
  1708.                CALL   DISPLAY_TEXT
  1709.  
  1710. WAIT_KEY:      CALL   READ_KEY               ;Get a response to message.
  1711.                CMP    AH,13H                 ;Was it scan code for "R"?
  1712.                JZ     END_DISK               ;If yes retry.
  1713.                CMP    AH,10H                 ;Was it "Q"?
  1714.                JNZ    WAIT_KEY               ;If no, wait until correct response
  1715.                JMP    EXIT                   ;Else, exit to DOS.
  1716.  
  1717. END_DISK:      CALL   CLEAR_MSG              ;Clear disk error message.
  1718.                POP    ES                     ;Restore registers.
  1719.                POP    DS
  1720.                POP    BP
  1721.                POP    DI
  1722.                POP    SI
  1723.                POP    DX
  1724.                POP    CX
  1725.                POP    BX
  1726.                POP    AX
  1727.                POPF
  1728.                MOV    AL,1                   ;Return with retry request.
  1729.                IRET
  1730.  
  1731. CURRENT_DIR    DB     0
  1732. WORKING_DIR    EQU    CURRENT_DIR+68
  1733. PURGE_DIR      EQU    WORKING_DIR+68
  1734. SOURCE         EQU    PURGE_DIR+66
  1735. TARGET         EQU    SOURCE+65+13
  1736. ENTRY          EQU    TARGET+65+13
  1737. BUFFER         EQU    ENTRY+36
  1738.  
  1739. CODE ENDS
  1740. END  START
  1741.